'''※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
File Name: api.py
Author: GID5564
Description: 
Version: 1.0
Created Time: 22/09/23-15:02:08
※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※'''
  
#! /usr/bin/python3
# -*- coding: UTF-8 -*-

import cv2
import os
import re
import datetime
import random
import sys
import math
import numpy as np
from PIL import ImageEnhance
from PIL import Image
import matplotlib.pyplot as  plt
import pytesseract
import concurrent.futures
from math import *
from scipy.stats import mode


from removebg import RemoveBg
import jieba #分词
import collections #词频统计
import wordcloud #生成词云
from MyQR import myqr

from amzqr import amzqr
from pathlib import Path

#自定义
#import ../func as f

##♦♦♦♦♦♦♦♦♦♦♦♦
##函数，类定义
##♦♦♦♦♦♦♦♦♦♦♦♦
class ImageOperate():
    #图片打开与保存
    def __init__(self,input_image_path,flag=1):
        try:
            self.img = cv2.imread(input_image_path,flag)
        except BaseException as e:
            print(e)
            
    def save_image(self,img,save_full_path,suffix='.png'):
        try:
            name = "Image_"+datetime.datetime.now().strftime('%Y%m%d%H%M%S')
            if not os.path.exists(save_full_path):
                os.makedirs(save_full_path)
            save_path=os.path.join(save_full_path,name)
            save_path=save_path+suffix
            cv2.imwrite(save_path,img)
        except BaseException as e:
            print(e)
 

def convert_to_3channel(img):
    '''
    功能: 将单通道图像转换为三通道图像
    参数: img:单通道图像
    返回: 三通道图像
    事例: (800,450)转换为(800,450,3)
    '''
    # 如果是灰度图，则使用 cv2.cvtColor() 函数将其转换为 BGR 彩色图像
    if len(img.shape) == 2:
        img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
    # 如果是带有 alpha 通道的图像，则使用 cv2.cvtColor() 函数将其转换为 BGR 彩色图像
    elif img.shape[2] == 4:
        img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
    # 如果是 RGB 彩色图像，则使用 cv2.merge() 函数将其转换为 BGR 彩色图像
    elif img.shape[2] == 3 and not cv2.cvtColor(img, cv2.COLOR_BGR2RGB).any():
        b, g, r = cv2.split(img)
        img = cv2.merge([r, g, b])
    # 如果已经是 BGR 彩色图像，则直接返回
    elif img.shape[2] == 3:
        pass
    # 如果不是上述类型，则返回 None
    else:
        return None
    return img


#九宫格切图制作
class JiuGongGePic(object):
    def __init__(self,image_file,save_dir):
        self.image_file=image_file
        self.image_list=[]
        self.result_dir=save_dir

   #将图片填充为正方形
    def __fill_image(self,image):
       # pass
        width, height = image.size    
       #选取长和宽中较大值作为新图片的
        new_image_length = width if width > height else height    
       #生成新图片[白底]
        new_image = Image.new(image.mode, (new_image_length, new_image_length), color='white')    
       #将之前的图粘贴在新图上，居中
        if width > height:#原图宽大于高，则填充图片的竖直维度
          #(x,y)二元组表示粘贴上图相对下图的起始位置
            new_image.paste(image, (0, int((new_image_length - height) / 2)))
        else:
            new_image.paste(image, (int((new_image_length - width) / 2),0))    
        return new_image
    #将图片切为9张
    def __cut_image(self,image):
       # pass
        width, height = image.size
        item_width = int(width / 3)
        box_list = []
       # (left, upper, right, lower)
        for i in range(0,3):#两重循环，生成9张图片基于原图的位置
            for j in range(0,3):
            #print((i*item_width,j*item_width,(i+1)*item_width,(j+1)*item_width))
                 box = (j*item_width,i*item_width,(j+1)*item_width,(i+1)*item_width)
                 box_list.append(box)
                 image_list = [image.crop(box) for box in box_list]
        return image_list

    '''
    对处理后的图片进行保存:当前工作目录+"/result/"
    '''
    def save_images(self,image_list):
        index = 1
        for image in image_list:
            image.save(self.result_dir+"/"+str(index) + '.png', 'PNG')
            index += 1

    def __open_image(self):
        image=Image.open(self.image_file)
        return image

    def cut_image(self):
        image=self.__open_image()
        image=self.__fill_image(image)
        self.image_list=self.__cut_image(image)
#词云图
class WordCloudPic(object):
    def __init__(self,txtfile,width,height,bg_mask,bg_color,font,save_path):
        self.txtfile=txtfile
        self.width=width
        self.height=height
        #可以打开你喜欢的词云展现背景图
        if  bg_mask :
            if os.path.exists(bg_mask):
                cloud_mask = np.array(Image.open(bg_mask))
                #背景图
            else:
                cloud_mask = None
                #形状
                #cloud_mask=(x-180)**2+(y-180)**2>180**2#圆形外部将被设置为背景色
                #cloud_mask=255*cloud_mask.astype(int)
        else:
            cloud_mask=None 
        
        self.cloud_mask=cloud_mask
        self.bg_color=bg_color
        self.font=font
        self.save=save_path
    
        #分词处理
    def cut_word(self):
        word_list=[] #词容器
         # 读取文本
        with open(self.txtfile,encoding="utf-8") as f:
            data = f.read()
        #过滤除汉字英文外所有字符   
        new_data = re.findall("[A-Za-z\u4e00-\u9fa5]+", data, re.S)
        #连接
        new_data = " ".join(new_data)
        #生成分词列表
        w_cut = jieba.cut(new_data,cut_all =False) 
        
        #再次过滤,去掉不需要显示的词
        stopwords = ["它","我们","他","了","我","你","她","的","是","了","在","也","和","就","都","这"," "] 
        for x in w_cut:
            if x not in stopwords:
                word_list.append(x)
                
        return word_list
        
    #词频统计
    def word_frequency_count(self,wl=[],top=50):
        word_counts = collections.Counter(wl) #词频统计
        word_counts_top = dict(word_counts.most_common(top)) #词云取前50的词
        return word_counts_top
        



    def WordCloudImage(self,top):
        #分词
        wordlist=self.word_frequency_count(self.cut_word(),top)
        #保存的词云图文件名
        file_name=f.get_random_file_name('png')
        # 定义词云的一些属性
        wc = wordcloud.WordCloud(width=self.width, # 图幅宽度 900
             height=self.height,  # 图幅高度 3000
             background_color=self.bg_color,  # 背景图分割颜色为白色 "black"
             mode="RGBA",
             mask=self.cloud_mask,  # 词么形状，默认矩形
             max_words=1000,  # 显示最大词数
             font_path=self.font,  # 显示中文
             collocations=False,
             #min_font_size=5, # 最小尺寸
             #max_font_size=100,  # 最大尺寸
             #stopwords = STOPWORDS,# 设置停用词，停用词则不再词云图中表示 也可以直接有字符串，设置停用词
             #random_state=1# 设置有多少种随机生成状态，即有多少种配色方案 
             ).generate_from_frequencies(wordlist)
        # 生成词云图片
        image = wc.to_image()
        # savepath是图片保存地址，保存词云图片
        wc.to_file(self.save+"/"+file_name)
        
class ImageFilter(ImageOperate):
    def __init__(self,input_image_path,flag=1):
        super().__init__(input_image_path,flag)

        
    #浮雕
    def relief(self):
        img=self.img.copy()
        kernel = np.array([[1, 0], [0, -1]])
        row = img.shape[0]
        col = img.shape[1]
        canvas = np.zeros([row, col], dtype=np.uint8)
        for i in range(row - 1):
            for j in range(col - 1):
                new_value = np.sum(img[i:i + 2, j:j + 2] * kernel) + 128
                if new_value > 255:
                    new_value = 255
                elif new_value < 0:
                    new_value = 0
                else:
                    pass
                canvas[i, j] = new_value
        return canvas
        
    
    #雕刻
    def carve(self):
        img=self.img.copy()
        kernel = np.array([[-1, 0], [0, 1]])
        row = img.shape[0]
        col = img.shape[1]
        canvas = np.zeros([row, col], dtype=np.uint8)
        for i in range(row - 1):
            for j in range(col - 1):
                new_value = np.sum(img[i:i + 2, j:j + 2] * kernel) + 128
                if new_value > 255:
                    new_value = 255
                elif new_value < 0:
                    new_value = 0
                else:
                    pass
                canvas[i, j] = new_value
        return canvas
        
    #凸透镜
    def convex_lens(self):
        img=self.img.copy()
        row = img.shape[0]
        col = img.shape[1]
        channel = img.shape[2]
        canvas = np.zeros([row, col, channel], dtype=np.uint8)
        center_x = row/2
        center_y = col/2
        radius = min(center_x, center_y)
        for i in range(row):
            for j in range(col):
                distance = ((i-center_x) * (i-center_x) + (j-center_y) * (j-center_y))
                new_dist = math.sqrt(distance)
                canvas[i,j,:] = img[i, j, :]
                if distance <= radius**2:
                    new_i = np.int64(np.floor(new_dist * (i-center_x) / radius + center_x))
                    new_j = np.int64(np.floor(new_dist * (j-center_y) / radius + center_y))
                    canvas[i,j,:] = img[new_i, new_j, :]
        return canvas
    
    #底片
    def negative_film(self):
        #底片
        img=self.img.copy()
        h, w, d = img.shape[:3]
        size = (h, w, d)
        iTmp = np.zeros(size, np.uint8)
        for i in range(h):
            for j in range(w):
                iTmp[i, j, 0] = 255 - img[i, j, 0]
                iTmp[i, j, 1] = 255 - img[i, j, 1]
                iTmp[i, j, 2] = 255 - img[i, j, 2]
        return iTmp
        
    #素描
    def sketch(self,sigmaX=5,ksize=0,sharpen_value=0):
        '''
        功能: 图像铅笔素描
        参数: 
            img: 图像(np.ndarray)
            sigma:控制色散量，模糊程度，值增加，图像变得更模糊。
            ksize: 内核大小
            sharpen_value: 锐化值
        返回: new_img，图像(np.ndarray)
        '''
        img=self.img.copy()
        #卷积核
        kernel = np.array([[0, -1, 0], [-1, sharpen_value,-1], [0, -1, 0]])
        #图像灰度处理
        gray =  cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
        #反转
        inverted_img = 255 - gray
        #高斯模糊图像
        blur_img = cv2.GaussianBlur(inverted_img, ksize=(ksize,ksize), sigmaX=sigmaX)

        #颜色亮化
        result = cv2.divide(gray,255-blur_img,scale=256)
        '''
        #颜色暗化
        #result=255-cv2.divide(255-gray,255-blur_img,scale=256)
        '''
        #通过降低对比度来加亮基色以反映混合色
        result[result>255] = 255
        result[gray==255] = 255
        final_img= result.astype('uint8')
    
        #锐化图像
        if sharpen_value is not None and isinstance(sharpen_value, int):
            inverted = 255 - final_img
            new_img= 255 - cv2.filter2D(src=inverted, ddepth=-1, kernel=kernel)
        else:
            new_img=final_img
    
        return new_img

    #怀旧
    def nostalgia(self):
        '''
        功能: 图像怀旧特效
        参数: 
            img: 图像(np.ndarray)
        返回: new_img，图像(np.ndarray)
        怀旧公式:
            R=0.393*r+0.769*g+0.189*b 
            G=0.349*r+0.686*g+0.168*b 
            B=0.272*r+0.534*g+0.131*b
        '''
        img=self.img.copy()
        #获取图像行和列
        rows,  cols =  img.shape[:2]
        #新建目标图像
        new_img =  np.zeros((rows,  cols, 3),  dtype="uint8")
        #图像怀旧特效
        for  i in range(rows):
            for  j in range(cols): 
                B = 0.272*img[i,j][2] + 0.534*img[i,j][1] + 0.131*img[i,j][0] 
                G = 0.349*img[i,j][2] + 0.686*img[i,j][1] + 0.168*img[i,j][0] 
                R = 0.393*img[i,j][2] + 0.769*img[i,j][1] + 0.189*img[i,j][0]
                if  B>255: 
                    B = 255
                if  G>255: 
                    G = 255
                if  R>255: 
                    R = 255 
                new_img[i,j] =  np.uint8((B,G,R))
        return new_img

    #光照
    def illumination(self,strength=200,center=(0.1,0.7)):
        '''
        功能: 图片缩放
        参数: 
            img: 图像(np.ndarray)
        
            strength: 光照强度
            center: (x,y)图片中心点,范围[0-1]
        返回: new_img，图像(np.ndarray)
        '''
        img=self.img.copy()
        #获取图像行和列
        rows,  cols =  img.shape[:2]
        #设置中心点
        centerX =  float(rows*center[0])
        centerY =  float(cols*center[1])
        radius = min(centerX,  centerY)
        #新建目标图像
        new_img =  np.zeros((rows,  cols, 3),  dtype="uint8")
        #图像光照特效
        for  i in range(rows):
            for  j in range(cols):
                #计算当前点到光照中心距离(平面坐标系中两点之间的距离#) 
                distance =  math.pow((centerY-j), 2) +  math.pow((centerX-i), 2)
                #获取原始图像
                B =  img[i,j][0] 
                G =  img[i,j][1] 
                R =  img[i,j][2]
                if (distance <  radius *  radius):
                    #按照距离大小计算增强的光照值 
                    result = (int)(strength*( 1.0 - math.sqrt(distance) /  radius )) 
                    B =  img[i,j][0] +  result
                    G =  img[i,j][1] +  result 
                    R =  img[i,j][2] +  result
                    #判断边界 防止越界
                    B = min(255, max(0,  B))
                    G = min(255, max(0,  G)) 
                    R = min(255, max(0,  R)) 
                    new_img[i,j] =  np.uint8((B,  G,  R))
                else: 
                    new_img[i,j] =  np.uint8((B,  G,  R))
        return new_img

    #流年
    def flowingyear(self,weight=12):
        '''
        功能: 图像流年特效
        参数: 
            img: 图像(np.ndarray)
            weight: 权重
        返回: new_img，图像(np.ndarray)
        '''
        img=self.img.copy()
        #获取图像行和列
        rows,  cols =  img.shape[:2]
        #新建目标图像
        new_img =  np.zeros((rows,  cols, 3),  dtype="uint8")
        #图像流年特效
        for  i in range(rows):
            for  j in range(cols):
                #B通道的数值开平方乘以参数12 
                B =  math.sqrt(img[i,j][0]) * weight
                G =  img[i,j][1] 
                R =  img[i,j][2]
                if  B>255: 
                    B = 255
                new_img[i,j] =  np.uint8((B,  G,  R))
        return new_img

    #油画
    def oilpaint(self,bucksize=8,step=2):
        '''
        功能: 油画
        参数: 
            img: 图像(np.ndarray)
            bucksize: 模板大小
            step: 步长
        返回: new_img，图像(np.ndarray)
        '''
        img=self.img.copy()
        new_img=cv2.xphoto.oilPainting(img,bucksize,step)
        return new_img

    #水彩画
    def stylization(self,sigma_s=60,sigma_r=0.6):
        '''
        功能: 水彩画
        参数: 
            img: 图像(np.ndarray)
            sigma_s: 控制邻域的大小。范围1-200
            sigma_r:控制邻域内不同颜色的平均方式。较大的sigma_r导致恒定颜色的较大区域。范围0-1
        返回: new_img，图像(np.ndarray)
        '''
        img=self.img.copy()
        new_img=cv2.stylization(img, sigma_s, sigma_r)
        return new_img
        
    # 毛玻璃特效
    def glass(self,coef):
        img=self.img.copy()
        h, w, d = img.shape[:3]
        m=int(w*coef/10)
        glassImg = np.zeros((h, w, 3), np.uint8)
        for i in range(h - m):
            for j in range(w - m):
                index = int(np.random.random() * m)
                glassImg[i, j] = img[i + index, j + index]
        return glassImg

    # 马赛克特效
    def mask(self,coef):
        img=self.img.copy()
        h, w, d = img.shape[:3]
        m=int(w*coef/10)
        maskImg = np.zeros((h, w, 3), np.uint8)
        for i in range(h - m): 
            for j in range(w - m):
                if i%m==0 and j%m==0 :
                    for k in range(m):
                        for t in range(m):
                            (b, g, r) = img[i, j]
                            maskImg[i + k, j + t] = (b, g, r)
        return maskImg

    # 卡通特效
    def cartoon(self,fnum=7):
        # fnum:双边滤波数目
        img=self.img.copy()
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        for i in range(fnum):
            cv2.bilateralFilter(img, d = 9, sigmaColor = 5, sigmaSpace = 3)
        median = cv2.medianBlur(gray, 7)
        edge = cv2.adaptiveThreshold(median, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, blockSize = 5, C = 2)
        edge = cv2.cvtColor(edge, cv2.COLOR_GRAY2RGB)
        return cv2.bitwise_and(img, edge)

        
    #黑白
    def monochrome(self,thresh=80,flag=True):
        '''
        功能: 图片转黑白图(黑字白底)
        参数: img: 图像(np.ndarray)
            thresh: 满足条件的像素点需要设置的灰度值。（将要设置的灰度值）取值0～255
        返回:new_img,图像(np.ndarray)
        '''
        img=self.img.copy()
        # 灰度化处理
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        # 图像反色
        h, w = gray.shape
        for i in range(h):
            for j in range(w):
                if flag:
                    gray[i, j] = 255 - gray[i, j]  # 黑字白底
                else:
                    gray[i, j] = gray[i, j] - 255  # 白字黑底

        ret, new_img = cv2.threshold(gray, thresh, 255, cv2.THRESH_BINARY)
        return new_img

class ImageMatting(ImageOperate):
    def __init__(self,input_image_path,flag=1):
        super().__init__(input_image_path,flag)

    def process_image(self,flag, new_background_color):
        image=self.img.copy()
        # 如果原图尺寸太大，可以进行图像压缩
        scale_percent = 50  # 压缩比例（50%）
 
        # 计算压缩后的图像尺寸
        width = int(image.shape[1] * scale_percent / 100)
        height = int(image.shape[0] * scale_percent / 100)
        dim = (width, height)
 
        # 调整图像尺寸
        resized_image = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
        if flag:
            # 换背景色
            result = self.grabcut_segmentation(resized_image, new_background_color)
        else:
            # 抠图
            result = self.matting(resized_image)
 
        # 返回处理结果
        return result
 
 
    def grabcut_segmentation(self,image, new_background_color):
        # 创建掩膜
        mask = np.zeros(image.shape[:2], np.uint8)
 
        # 定义GrabCut算法所需的前景和背景模型
        bgd_model = np.zeros((1, 65), np.float64)
        fgd_model = np.zeros((1, 65), np.float64)
 
        # 定义矩形区域，包含前景对象（根据实际需要调整矩形位置和大小）
        height, width = image.shape[:2]
        rect = (10, 10, width - 10, height - 10)
 
        # 执行GrabCut算法, 通过调整num_iterations参数来控制迭代次数，以平衡速度和准确性
        num_iterations = 5
        cv2.grabCut(image, mask, rect, bgd_model, fgd_model, num_iterations, cv2.GC_INIT_WITH_RECT)
 
        # 创建前景和背景掩膜
        mask_foreground = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
        mask_background = 1 - mask_foreground
 
        # 创建纯色背景图像
        background = np.zeros_like(image, np.uint8)
        background[:] = new_background_color
 
        # 将前景放在白色背景上
        foreground = cv2.bitwise_and(image, image, mask=mask_foreground)
        result = cv2.add(foreground, cv2.bitwise_and(background, background, mask=mask_background))
 
        return foreground #result
        
    def matting(self,image):
        # 创建掩膜
        mask = np.zeros(image.shape[:2], np.uint8)
 
        # 定义GrabCut算法所需的前景和背景模型
        bgd_model = np.zeros((1, 65), np.float64)
        fgd_model = np.zeros((1, 65), np.float64)
 
        # 定义矩形区域，包含前景对象（根据实际需要调整矩形位置和大小）
        height, width = image.shape[:2]
        rect = (10, 10, width - 10, height - 10)
 
        # 执行GrabCut算法, 通过调整num_iterations参数来控制迭代次数，以平衡速度和准确性
        num_iterations = 5
        cv2.grabCut(image, mask, rect, bgd_model, fgd_model, num_iterations, cv2.GC_INIT_WITH_RECT)
 
        # 创建前景和背景掩膜
        mask_foreground = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
        mask_background = 1 - mask_foreground
 
        # 将前景放在白色背景上
        result = cv2.bitwise_and(image, image, mask=mask_foreground)

        return result
        
class DeShadowing(ImageOperate):
    def __init__(self,input_image_path,flag=1):
        super().__init__(input_image_path,flag)
    
    def _max_filtering(self,N, I_temp):
        #最大滤波
        wall = np.full((I_temp.shape[0]+(N//2)*2, I_temp.shape[1]+(N//2)*2), -1)
        wall[(N//2):wall.shape[0]-(N//2), (N//2):wall.shape[1]-(N//2)] = I_temp.copy()
        temp = np.full((I_temp.shape[0]+(N//2)*2, I_temp.shape[1]+(N//2)*2), -1)
        for y in range(0,wall.shape[0]):
            for x in range(0,wall.shape[1]):
                if wall[y,x]!=-1:
                    window = wall[y-(N//2):y+(N//2)+1,x-(N//2):x+(N//2)+1]
                    num = np.amax(window)
                    temp[y,x] = num
        A = temp[(N//2):wall.shape[0]-(N//2), (N//2):wall.shape[1]-(N//2)].copy()
        return A

    def _min_filtering(self,N, A):
        #最小滤波
        wall_min = np.full((A.shape[0]+(N//2)*2, A.shape[1]+(N//2)*2), 300)
        wall_min[(N//2):wall_min.shape[0]-(N//2), (N//2):wall_min.shape[1]-(N//2)] = A.copy()
        temp_min = np.full((A.shape[0]+(N//2)*2, A.shape[1]+(N//2)*2), 300)
        for y in range(0,wall_min.shape[0]):
            for x in range(0,wall_min.shape[1]):
                if wall_min[y,x]!=300:
                    window_min = wall_min[y-(N//2):y+(N//2)+1,x-(N//2):x+(N//2)+1]
                    num_min = np.amin(window_min)
                    temp_min[y,x] = num_min
        B = temp_min[(N//2):wall_min.shape[0]-(N//2), (N//2):wall_min.shape[1]-(N//2)].copy()
        return B

    def _background_subtraction(self,I, B):
        #归一化，使用背景减法获得的最终阵列，该方法是将原始图像减去最小-最大滤波图像
        O = I - B
        norm_img = cv2.normalize(O, None, 0,255, norm_type=cv2.NORM_MINMAX)
        return norm_img

    def min_max_filtering(self,I,M, N):
        if M == 0:
            #max_filtering
            A = self._max_filtering(N, I)
            #min_filtering
            B = self._min_filtering(N, A)
            #subtraction
            normalised_img = self._background_subtraction(I, B)
        elif M == 1:
            #min_filtering
            A = self._min_filtering(N, I)
            #max_filtering
            B = self._max_filtering(N, A)
            #subtraction
            normalised_img = self._background_subtraction(I, B)
        return normalised_img

    def remove_shadow(self,img,M=0,N=15):
        '''
        功能: 图片去阴影
        参数: img: 图像(np.ndarray)
            M: 0,图像背景较浅且对象较暗;1,图像背景较暗且物体较亮
            N:（像素周围的N x N邻域，用于过滤的窗口大小）将根据图像中粒子或内容的大小进行更改
        返回:new_img,图像(np.ndarray)
        '''
        # 灰度化处理
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        new_img=self.min_max_filtering(gray,M,N)
        return new_img

class ImageRectification(ImageOperate):
    def __init__(self,input_image_path,flag=1):
        super().__init__(input_image_path,flag)
    
    # 固定尺寸
    def _resizeImg(self,img, height=900):
        h, w = img.shape[:2]
        pro = height / h
        size = (int(w * pro), int(height))
        new_img = cv2.resize(img, size)
        return new_img

    # 边缘检测
    def _getCanny(self,img):
        # 高斯模糊
        gaus = cv2.GaussianBlur(img, (3, 3), 2, 2)
        # 边缘检测
        cann = cv2.Canny(gaus, 60, 240, apertureSize=3)
        # 膨胀操作，尽量使边缘闭合
        kernel = np.ones((3, 3), np.uint8)
        binary = cv2.dilate(cann, kernel, iterations=1)
        return binary

    #求图像聊有mask边界轮廓
    def _extract_contour(self,img):
        """
        功能: 取得图像的所有mask的边界轮廓矩阵
        参数: img,图像(np.ndarray)
        返回: contours,图像边界轮廓矩阵
        """
        rgb = cv2.cvtColor(np.asarray(img),cv2.COLOR_RGB2BGR)
    
        gray        = cv2.cvtColor(rgb, cv2.COLOR_BGR2GRAY) # 彩色图变灰度图
        _,binary    = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) # 灰度图变二值图
        contours, _ = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 根据二值图找轮廓
        # cv2.drawContours(img,contours,-1,(0,0,255),1) # 把轮廓画在原图上（0,0,255） 表示 RGB 三通道，红色
        return contours


    # 求出面积最大的轮廓
    def _findMaxContour(self,img):
        # 寻找边缘
        contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
        # 计算面积
        max_area = 0.0
        max_contour = []
        for contour in contours:
            currentArea = cv2.contourArea(contour)
            if currentArea > max_area:
                max_area = currentArea
                max_contour = contour
        return max_contour, max_area

    # 多边形拟合凸包的四个顶点
    def _getBoxPoint(self,contour,preci=0.02):
        # 多边形拟合凸包
        hull = cv2.convexHull(contour)
        epsilon = preci * cv2.arcLength(contour, True)
        approx = cv2.approxPolyDP(hull, epsilon, True)
        approx = approx.reshape((len(approx), 2))
        return approx

    # 适配原四边形点集
    def _adaPoint(self,box, pro):
        box_pro = box
        if pro != 1.0:
            box_pro = box/pro
        box_pro = np.trunc(box_pro)
        return box_pro

    def _four_point_transform(self,img, pts):
        #参考ref[1]
        # 获取坐标点，并将它们分离开来
        rect = self._orderPoints(pts)
        (tl, tr, br, bl) = rect
 
        # 计算新图片的宽度值，选取水平差值的最大值
        widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
        widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
        maxWidth = max(int(widthA), int(widthB))
 
        # 计算新图片的高度值，选取垂直差值的最大值
        heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
        heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
        maxHeight = max(int(heightA), int(heightB))
 
        # 构建新图片的4个坐标点
        dst = np.array([[0, 0],[maxWidth - 1, 0],[maxWidth - 1, maxHeight - 1],[0, maxHeight - 1]], dtype = "float32")
 
        # 获取仿射变换矩阵并应用它
        M = cv2.getPerspectiveTransform(rect, dst)
        # 进行仿射变换
        warped = cv2.warpPerspective(img, M, (maxWidth, maxHeight))
 
        # 返回变换后的结果
        return warped
 
    # 四边形顶点排序，[top-left, top-right, bottom-right, bottom-left]
    def _orderPoints(self,pts):
        # 参考ref[1]
        # 初始化坐标点
        rect = np.zeros((4, 2), dtype = "float32")
 
        # 获取左上角和右下角坐标点
        s = pts.sum(axis = 1)
        rect[0] = pts[np.argmin(s)]
        rect[2] = pts[np.argmax(s)]
 
        # 分别计算左上角和右下角的离散差值
        diff = np.diff(pts, axis = 1)
        rect[1] = pts[np.argmin(diff)]
        rect[3] = pts[np.argmax(diff)]
 
        return rect

    # 计算长宽
    def _pointDistance(self,a, b):
        return int(np.sqrt(np.sum(np.square(a - b))))


    # 透视变换
    def _warpImage(self,img, box):
        w, h = self._pointDistance(box[0], box[1]),self._pointDistance(box[1], box[2])
        dst_rect = np.array([[0, 0],[w - 1, 0],[w - 1, h - 1],[0, h - 1]], dtype='float32')
        M = cv2.getPerspectiveTransform(box, dst_rect)
        warped = cv2.warpPerspective(img, M, (w, h))
        return warped

    def image_rectification_rectangle(self,src_img):
        '''
        功能: 图片校正，适用有明显边界的图片
        参数: 
        src_img: 图像(np.ndarray)
        返回: new_img，图像(np.ndarray)
        '''
    
        #图片固定高度，以适配边缘检测的阈值
        ratio = 900 / src_img.shape[0]
        img = self._resizeImg(src_img)
    
        #边缘检测
        binary_img = self._getCanny(img)
    
        # 求出面积最大的轮廓
        max_contour, max_area = self._findMaxContour(binary_img)
    
        # 多边形拟合凸包的四个顶点
        boxes = self._getBoxPoint(max_contour)
    
        # 适配原四边形点集
        boxes = self._adaPoint(boxes, ratio)
        # 四边形顶点排序，[top-left, top-right, bottom-right, bottom-left]
        boxes = self._orderPoints(boxes)
        # 透视变化
        new_img = self._warpImage(src_img, boxes)
        return new_img

class ImageCorrect(ImageOperate):

    def __init__(self, input_image_path,flag=1):
        try:
            self.img = cv2.imread(input_image_path,flag)
        except BaseException as e:
            print(e)
            
        self.h, self.w, self.channel = self.img.shape
        if self.w <= self.h:
            self.scale = 700 / self.w
            self.w_scale = 700
            self.h_scale = self.h * self.scale
            self.img = cv2.resize(self.img, (0, 0), fx=self.scale, fy=self.scale, interpolation=cv2.INTER_NEAREST)
        else:
            self.scale = 700 / self.h
            self.h_scale = 700
            self.w_scale = self.w * self.scale
            self.img = cv2.resize(self.img, (0, 0), fx=self.scale, fy=self.scale, interpolation=cv2.INTER_NEAREST)
        self.gray = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY)
 
 
    def img_lines(self):
        ret, binary = cv2.threshold(self.gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
        # cv2.imshow("bin",binary)
        kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))  # 矩形结构
        binary = cv2.dilate(binary, kernel)  # 膨胀
        edges = cv2.Canny(binary, 50, 200)
        # cv2.imshow("edges", edges)
        self.lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength=100, maxLineGap=20)
        print(self.lines)
        if self.lines is None:
            print("Line segment not found")
            return None
 
        lines1 = self.lines[:, 0, :]  # 提取为二维
        # print(lines1)
        imglines = self.img.copy()
        for x1, y1, x2, y2 in lines1[:]:
            cv2.line(imglines, (x1, y1), (x2, y2), (0, 255, 0), 3)
        return imglines
 
    def search_lines(self):
        lines = self.lines[:, 0, :]  # 提取为二维
        # k = [(y2 - y1) / (x2 - x1) for x1, y1, x2, y2 in lines]
        # sorted_k = sorted(lines, key=lambda x:(x[3] - x[1]) / (x[2] - x[0]))
        number_inexistence_k = 0
        sum_positive_k45 = 0
        number_positive_k45 = 0
        sum_positive_k90 = 0
        number_positive_k90 = 0
        sum_negative_k45 =0
        number_negative_k45 = 0
        sum_negative_k90 = 0
        number_negative_k90 = 0
        sum_zero_k = 0
        number_zero_k = 0
        for x in lines:
            if x[2] == x[0]:
                number_inexistence_k += 1
                continue
            print(degrees(atan((x[3] - x[1]) / (x[2] - x[0]))),"pos:",x[0],x[1],x[2],x[3],"斜率:",(x[3] - x[1]) / (x[2] - x[0]))
            if 0 < degrees(atan((x[3] - x[1]) / (x[2] - x[0]))) < 45:
                number_positive_k45 +=1
                sum_positive_k45 += degrees(atan((x[3] - x[1]) / (x[2] - x[0])))
            if 45 <= degrees(atan((x[3] - x[1]) / (x[2] - x[0]))) < 90:
                number_positive_k90 += 1
                sum_positive_k90 += degrees(atan((x[3] - x[1]) / (x[2] - x[0])))
            if -45 < degrees(atan((x[3] - x[1]) / (x[2] - x[0]))) < 0:
                number_negative_k45 += 1
                sum_negative_k45 += degrees(atan((x[3] - x[1]) / (x[2] - x[0])))
            if -90 < degrees(atan((x[3] - x[1]) / (x[2] - x[0]))) <= -45:
                number_negative_k90 += 1
                sum_negative_k90 += degrees(atan((x[3] - x[1]) / (x[2] - x[0])))
            if x[3] == x[1]:
                number_zero_k += 1
 
        max_number = max(number_inexistence_k,number_positive_k45, number_positive_k90, number_negative_k45, number_negative_k90,number_zero_k)
        # print(number_inexistence_k,number_positive_k45, number_positive_k90, number_negative_k45, number_negative_k90,number_zero_k)
        if max_number == number_inexistence_k:
            return 90
        if max_number == number_positive_k45:
            return sum_positive_k45 / number_positive_k45
        if max_number == number_positive_k90:
            return sum_positive_k90 / number_positive_k90
        if max_number == number_negative_k45:
            return sum_negative_k45 / number_negative_k45
        if max_number == number_negative_k90:
            return sum_negative_k90 / number_negative_k90
        if max_number == number_zero_k:
            return 0
 
    def rotate_image(self,degree):
        """
        正角 逆时针旋转
        :param degree:
        :return:
        """
        print("degree:", degree)
        if -45 <= degree <= 0:
            degree = degree # #负角度 顺时针
        if -90<= degree < -45:
            degree = 90 + degree #正角度 逆时针
        if 0 < degree <= 45:
            degree = degree #正角度 逆时针
        if 45 < degree <90:
            degree = degree - 90 #负角度 顺时针
        print("rotate degree:", degree)
        # degree = -45
        # # 获取旋转后4角的填充色
        filled_color = -1
        if filled_color == -1:
            filled_color = mode([self.img[0, 0], self.img[0, -1],
                                 self.img[-1, 0], self.img[-1, -1]]).mode[0]
        if np.array(filled_color).shape[0] == 2:
            if isinstance(filled_color, int):
                filled_color = (filled_color, filled_color, filled_color)
        else:
            filled_color = tuple([int(i) for i in filled_color])
 
        # degree = degree - 90
        height, width = self.img.shape[:2]
        heightNew = int(width * fabs(sin(radians(degree))) + height * fabs(cos(radians(degree))))  # 这个公式参考之前内容
        widthNew = int(height * fabs(sin(radians(degree))) + width * fabs(cos(radians(degree))))
 
        matRotation = cv2.getRotationMatrix2D((width / 2, height / 2), degree, 1) #逆时针旋转 degree
 
        matRotation[0, 2] += (widthNew - width) / 2  # 因为旋转之后,坐标系原点是新图像的左上角,所以需要根据原图做转化
        matRotation[1, 2] += (heightNew - height) / 2
 
        imgRotation = cv2.warpAffine(self.img, matRotation, (widthNew, heightNew), borderValue=filled_color)
        # imgRotation = cv2.warpAffine(self.img, matRotation, (widthNew, heightNew), borderValue=(255, 255, 255))
 
        # 填充四个角
        # mask = np.zeros((heightNew + 2, widthNew + 2), np.uint8)
        # mask[:] = 0
        # seed_points = [(0, 0), (0, heightNew - 1), (widthNew - 1, 0),
        #                (widthNew - 1, heightNew - 1)]
        # for i in seed_points:
        #     cv2.floodFill(imgRotation, mask, i, filled_color)
 
        # cv2.imwrite("./image/r14a.jpg", imgRotation)
        return imgRotation



class ImageEnhancement(ImageOperate):
    def __init__(self,input_image_path,flag=1):
        super().__init__(input_image_path,flag)
    #直方图均衡化
    def hist(self):
        img=self.img.copy()
        r, g, b = cv2.split(img)
        r1 = cv2.equalizeHist(r)
        g1 = cv2.equalizeHist(g)
        b1 = cv2.equalizeHist(b)
        new_img = cv2.merge([r1, g1, b1])
        return new_img
        
    def clahe(self):
        img=self.img.copy()
        # 将图像从 BGR 转换为 LAB
        lab_image = cv2.cvtColor(img, cv2.COLOR_BGR2Lab)
        # 将 LAB 图像拆分为单独的通道
        l_channel, a_channel, b_channel = cv2.split(lab_image)

        # 对每个通道应用自适应直方图均衡化
        clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
        l_channel = clahe.apply(l_channel)
        a_channel = clahe.apply(a_channel)
        b_channel = clahe.apply(b_channel)

        # 将处理后的通道重新组合为 LAB 图像
        lab_image = cv2.merge((l_channel, a_channel, b_channel))

        # 将图像从 LAB 转换回 BGR
        result_image = cv2.cvtColor(lab_image, cv2.COLOR_Lab2BGR)
        
        return result_image
        
    def log(self):
        img=self.img.copy()
        image_log = np.uint8(np.log(np.array(img) + 1))
        cv2.normalize(image_log, image_log, 0, 255, cv2.NORM_MINMAX)
        # 转换成8bit图像显示
        cv2.convertScaleAbs(image_log, image_log)
        return image_log

##♦♦♦♦♦♦♦♦♦♦♦♦
##函数，类事例
##♦♦♦♦♦♦♦♦♦♦♦♦

#♥九宫格切图制作       
def JiuGongGe(input_image_full_path,output_image_full_dir):
    '''
    功能: 九宫格切图制作
    参数:
            input_image_full_path,完整图片地址
            output_image_full_dir,切图保存完整目录
    返回:
    '''
    if not os.path.exists(input_image_full_path):
        return False

    if not f.is_image_file(input_image_full_path):
        return False
        
    if not os.path.exists(output_image_full_dir):
            os.makedirs(output_image_full_dir)
    pic=JiuGongGePic(input_image_full_path,output_image_full_dir)
    pic.cut_image()
    pic.save_images(pic.image_list)
    return True


#♥制作词云图
def WordCloud(txtfile,font=None,width=300,height=450,bg_mask=None,bg_color="white",top=50,save_path=None):
    '''
    功能:制作词云图
    参数:txtfile,文本文件
         width,height,图的宽度和高度
         bg_mask,词云图形状，形状底图
         bg_color,词云图背景色，默认白色
         font,字体文件
         top,排名靠前数量的词
         save_path,词云图保存地址
    返回:
    '''
    if  not os.path.exists(txtfile):
        return False
    if not save_path:
        save_path=f.getcurpath()
    if not os.path.exists(save_path):
            os.makedirs(save_path)
    wc=WordCloudPic(txtfile,width,height,bg_mask,bg_color,font,save_path)
    wc.WordCloudImage(top)
    return True

#♥二维码图
def special_2D_code(words,size=5,bg_image=None,save_dir=f.getcurpath()):
    file_name=f.get_random_file_name('png')
    if bg_image and not f.is_image_file(bg_image):
        bg_image=None

    version,level,qr=myqr.run(words=words,#扫描二维码后展示的内容，可以是网页链接，也可以是文字描述
        version=size,#生成二维码的边长，范围是1至40，数字越大边长越大
        picture=bg_image,#自定义二维码背景图，支持格式为 .jpg，.png，.bmp，.gif
        level='H',#二维码纠错级别，范围为['L','M','Q','H']，H为最高级默认选项。      
        colorized=True,#二维码背景颜色，默认为 False，即黑白色,开启 True ,生成彩色二维码
        save_name=file_name,#生成二维码名称:*.gif，*.png
        save_dir=save_dir#生成二维码路径，默认为程序当前路径，注意同名文件会覆盖旧的。
        )
    #print(f"二维码保存目录: {save_dir}")
    return True
    
def generate_qr(mode: str = 'default',words: str = None,version: int = None,level: str = None,picture_dir: str = None,picture: str = None,contrast: float = None,brightness: float = None,save_name: str = None,save_dir: str = None):

    '''
    用于控制二维码图片的生成
    :param mode: 模式，可选的有default（常规二维码static（静态底图）和motion（动态底图），默认为default
    :param words: 二维码需要嵌入的信息
    :param version: 边长大小，取值在1到40之间，越大图片越精细
    :param level: 纠错水平，可选的有L、M、Q、H，从左往右越大越精准
    :param picture_dir: 底图文件的绝对路径
    :param picture: 底图文件名
    :param contrast: 对比度，取值在0到1之间
    :param brightness: 亮度，取值在0到1之间
    :param save_name: 导出文件名
    :param save_dir: 导出文件绝对路径
    :return:
    '''

    # mode: default
    if mode == 'default':

        _ = amzqr.run(
            words=words,
            version=version,
            level=level,
            save_name=save_name,
            save_dir=save_dir
        )

    # mode: static | motion
    elif mode == 'static' or mode == 'motion':
        #表示当前的工作目录，并将其绝对路径赋值给变量origin。
        origin = Path().absolute()
        #将当前工作目录更改为caches目录下的picture_dir子目录
        os.chdir(Path('caches', picture_dir))

        _ = amzqr.run(
            words=words,
            version=version,
            level=level,
            picture=picture,
            colorized=True,
            contrast=contrast,
            brightness=brightness,
            save_name=save_name,
            save_dir=os.getcwd()
        )

        os.chdir(origin)
    return True


#浮雕♥
def filter_embossment(image_full_path,save_path=f.getcurpath()):
    
    cif=ImageFilter(image_full_path,cv2.IMREAD_GRAYSCALE)
    img=cif.relief()
    cif.save_image(img,save_path)
    return True
    
#雕刻♥
def filter_carve(image_full_path,save_path=f.getcurpath()):
    
    cif=ImageFilter(image_full_path,cv2.IMREAD_GRAYSCALE)
    img=cif.carve()
    cif.save_image(img,save_path)
    return True

#凸透镜♥
def filter_convex_lens(image_full_path,save_path=f.getcurpath()):
    
    cif=ImageFilter(image_full_path,cv2.IMREAD_COLOR)
    img=cif.convex_lens()
    cif.save_image(img,save_path)
    return True

#底片♥
def filter_negative_film(image_full_path,save_path=f.getcurpath()):
    
    cif=ImageFilter(image_full_path,cv2.IMREAD_COLOR)
    img=cif.negative_film()
    cif.save_image(img,save_path)
    return True

#素描♥
def filter_sketch(image_full_path,sigmaX=5,ksize=(0,0),sharpen_value=None,save_path=f.getcurpath()):
    
    cif=ImageFilter(image_full_path,cv2.IMREAD_COLOR)
    img=cif.sketch(sigmaX=sigmaX,ksize=ksize,sharpen_value=sharpen_value)
    cif.save_image(img,save_path)
    return True

#怀旧♥
def filter_nostalgia(image_full_path,save_path=f.getcurpath()):
    
    cif=ImageFilter(image_full_path,cv2.IMREAD_COLOR)
    img=cif.nostalgia()
    cif.save_image(img,save_path)
    return True

#光照♥
def filter_illumination(image_full_path,strength=200,Xcenter=0.5,Ycenter=0.5,save_path=f.getcurpath()):
    
    cif=ImageFilter(image_full_path,cv2.IMREAD_COLOR)
    img=cif.illumination(strength=strength,center=(Xcenter,Ycenter))
    cif.save_image(img,save_path)
    return True
    
#流年♥
def filter_flowingyear(image_full_path,weight=12,save_path=f.getcurpath()):
    
    cif=ImageFilter(image_full_path,cv2.IMREAD_COLOR)
    img=cif.flowingyear(weight=weight)
    cif.save_image(img,save_path)
    return True

#油画♥
def filter_oilpaint(image_full_path,bucksize=8,step=2,save_path=f.getcurpath()):
    
    cif=ImageFilter(image_full_path,cv2.IMREAD_COLOR)
    img=cif.oilpaint(bucksize=bucksize,step=step)
    cif.save_image(img,save_path)
    return True
    
#水彩画♥
def filter_stylization(image_full_path,sigma_s=60,sigma_r=0.6,save_path=f.getcurpath()):
    
    cif=ImageFilter(image_full_path,cv2.IMREAD_COLOR)
    img=cif.stylization(sigma_s=sigma_s,sigma_r=sigma_r)
    cif.save_image(img,save_path)
    return True

#毛玻璃♥
def filter_glass(image_full_path,coef=0.1,save_path=f.getcurpath()):
    
    cif=ImageFilter(image_full_path,cv2.IMREAD_COLOR)
    img=cif.glass(coef)
    cif.save_image(img,save_path)
    return True

#马塞克♥
def filter_mask(image_full_path,coef=0.1,save_path=f.getcurpath()):
    
    cif=ImageFilter(image_full_path,cv2.IMREAD_COLOR)
    img=cif.mask(coef)
    cif.save_image(img,save_path)
    return True

#卡通♥
def filter_cartoon(image_full_path,fnum=7,save_path=f.getcurpath()):
    
    cif=ImageFilter(image_full_path,cv2.IMREAD_COLOR)
    img=cif.cartoon(fnum)
    cif.save_image(img,save_path)
    return True

#黑白♥
def filter_monochrome(image_full_path,thresh=80,flag=True,save_path=f.getcurpath()):
    
    cif=ImageFilter(image_full_path,cv2.IMREAD_COLOR)
    img=cif.monochrome(thresh,flag)
    cif.save_image(img,save_path)
    return True

#照片去背景♥
def remove_background(image_full_path,save_path=f.getcurpath()):
    
    mt=ImageMatting(image_full_path,cv2.IMREAD_COLOR)
    # 使用多线程处理单张照片
    with concurrent.futures.ThreadPoolExecutor() as executor:
        result = executor.submit(mt.process_image, False,None)
    
    mt.save_image(result.result(),save_path)
    return True
    



#⁉️抠图♥
def image_matting(input_image_path: str,save_full_path:str):

    
    img = cv2.imread(input_image_path,cv2.IMREAD_COLOR)

    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    cv2.imwrite("/home/save/hsv.png",hsv)

    # 根据像素的范围进行过滤，把符合像素范围的保留，不符合的赋值0或者255
    #⁉️要去除颜色的上限和下限
    lower_color=np.array([125,43,46])
    upper_color=np.array([155,255,255])

    # 根据hsv颜色表找出最大值和最小值
    mask = cv2.inRange(hsv, lower_color, upper_color)
    #闭运算
    kernel=np.ones((5,5),np.uint8)
    r=cv2.morphologyEx(mask,cv2.MORPH_CLOSE,kernel)
    
    mask = cv2.bitwise_not(mask)

    # 只在mask区域做与运算
    result = cv2.bitwise_and(img, img, mask=mask)

    
    name = "Image_"+datetime.datetime.now().strftime('%Y%m%d%H%M%S')
    if not os.path.exists(save_full_path):
            os.makedirs(save_full_path)
    save_path=os.path.join(save_full_path,name)
    save_path=save_path+".png"
    cv2.imwrite(save_path,result)
    return True

    
#换背景色♥
def change_background_color(image_full_path,new_color,save_path=f.getcurpath()):
    
    mt=ImageMatting(image_full_path,cv2.IMREAD_COLOR)
    # 使用多线程处理单张照片
    with concurrent.futures.ThreadPoolExecutor() as executor:
        result = executor.submit(mt.process_image, True,new_color)
    
    mt.save_image(result.result(),save_path)
    return True

#去除阴影♥
def remove_shadow(image_full_path,M,N,save_path):
    ds=DeShadowing(image_full_path,cv2.IMREAD_COLOR)
    img=ds.remove_shadow(ds.img,M,N)
    ds.save_image(img,save_path)
    return True
        
#图片校正(有明显边界)♥
def image_rectification(image_full_path,save_path):
    ir=ImageRectification(image_full_path,cv2.IMREAD_COLOR)
    img=ir.image_rectification_rectangle(ir.img)
    ir.save_image(img,save_path)
    return True

#图片文本倾斜校正(无明显边界)♥
def image_correct(image_full_path,save_path):
    ic=ImageCorrect(image_full_path,cv2.IMREAD_COLOR)
    lines_img = ic.img_lines()
    if lines_img is None:
        img=ic.rotate_image(0)
    else:
        degree = ic.search_lines()
        img=ic.rotate_image(degree)
    ic.save_image(img,save_path)
    return True
        
#直方图hist♥
def image_hist(image_full_path,save_path):
    ie=ImageEnhancement(image_full_path, cv2.IMREAD_COLOR)
    img=ie.hist()
    ie.save_image(img,save_path)
    return True
    
#自适应直方图clahe♥
def image_clahe(image_full_path,save_path):
    ie=ImageEnhancement(image_full_path, cv2.IMREAD_COLOR)
    img=ie.clahe()
    ie.save_image(img,save_path)
    return True
    
#对数变换♥
def image_log(image_full_path,save_path):
    ie=ImageEnhancement(image_full_path, cv2.IMREAD_COLOR)
    img=ie.log()
    ie.save_image(img,save_path)
    return True






if __name__=="__main__":
    assert len(sys.argv)>2,"参数错误!"
    op=sys.argv[1] #功能类型
    ret=False
    if op == 'JIUGONGGE':
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        save=sys.argv[3]
        ret=JiuGongGe(image,save)
        print(ret)
        
    elif op == 'WORDCLOUD':
        if len(sys.argv)<10:
            sys.exit("缺少参数!")
        txtfile=sys.argv[2]
        font=sys.argv[3]
        width=int(sys.argv[4])
        height=int(sys.argv[5])
        bg_mask=sys.argv[6]
        bg_color=sys.argv[7]
        top=int(sys.argv[8])
        save=sys.argv[9]
        ret=WordCloud(txtfile,font=font,width=width,height=height,bg_mask=bg_mask,bg_color=bg_color,top=top,save_path=save)
        print(ret)
        
    elif op == '2DCODE':
        if len(sys.argv)<6:
            sys.exit('缺少参数!')
        words=sys.argv[2]
        size=int(sys.argv[3])
        bg_image=sys.argv[4]
        save=sys.argv[5]
        ret=special_2D_code(words,size=size,bg_image=bg_image,save_dir=save)
        print(ret)
        
    elif op == "EMBOSSMENT":
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        save=sys.argv[3]
        ret=filter_embossment(image,save_path=save)
        print(ret)
    
    elif op == "CARVE":
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        save=sys.argv[3]
        ret=filter_carve(image,save_path=save)
        print(ret)
    
    elif op == "CONVEXLENS":
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        save=sys.argv[3]
        ret=filter_convex_lens(image,save_path=save)
        print(ret)
        
    elif op == "NEGATIVEFILM":
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        save=sys.argv[3]
        ret=filter_negative_film(image,save_path=save)
        print(ret)

    elif op == "SKETCH":
        if len(sys.argv)<7:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        sigmaX=int(sys.argv[3])
        ksize=int(sys.argv[4])
        sharpen_value=int(sys.argv[5])
        save=sys.argv[6]
        ret=filter_sketch(image,sigmaX=sigmaX,ksize=ksize,sharpen_value=sharpen_value,save_path=save)
        print(ret)
    
    elif op == "NOSTALGIA":
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        save=sys.argv[3]
        ret=filter_nostalgia(image,save_path=save)
        print(ret)
    
    elif op == "ILLUMINATION":
        if len(sys.argv)<7:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        strength=int(sys.argv[3])
        Xcenter=float(sys.argv[4])
        Ycenter=float(sys.argv[5])
        save=sys.argv[6]
        ret=filter_illumination(image,strength=strength,Xcenter=Xcenter,Ycenter=Ycenter,save_path=save)
        print(ret)
        
    elif op == "FLOWINGYEAR":
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        weight=int(sys.argv[3])
        save=sys.argv[4]
        ret=filter_flowingyear(image,weight=weight,save_path=save)
        print(ret)
        
    elif op == "OILPAINT":
        if len(sys.argv)<6:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        bucksize=int(sys.argv[3])
        step=int(sys.argv[4])
        save=sys.argv[5]
        ret=filter_oilpaint(image,bucksize=bucksize,step=step,save_path=save)
        print(ret)
        
    elif op == "STYLIZATION":
        if len(sys.argv)<6:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        sigma_s=int(sys.argv[3])
        sigma_r=float(sys.argv[4])
        save=sys.argv[5]
        ret=filter_stylization(image,sigma_s=sigma_s,sigma_r=sigma_r,save_path=save)
        print(ret)
        
    elif op == "GLASS":
        if len(sys.argv)<5:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        coef=float(sys.argv[3])
        save=sys.argv[4]
        ret=filter_glass(image,coef=coef,save_path=save)
        print(ret)
        
    elif op == "MASK":
        if len(sys.argv)<5:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        coef=float(sys.argv[3])
        save=sys.argv[4]
        ret=filter_mask(image,coef=coef,save_path=save)
        print(ret)
        
    elif op == "CARTOON":
        if len(sys.argv)<5:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        fnum=int(sys.argv[3])
        save=sys.argv[4]
        ret=filter_cartoon(image,fnum=fnum,save_path=save)
        print(ret)
    
    elif op == "MONOCHROME":
        if len(sys.argv)<6:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        thresh=int(sys.argv[3])
        if sys.argv[4].lower()=="false":
            flag=False
        else:
            flag=True
        save=sys.argv[5]
        ret=filter_monochrome(image,thresh=thresh,flag=flag,save_path=save)
        print(ret)
    
    elif op == "REMOVEBG":
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        save=sys.argv[3]
        ret=remove_background(image,save_path=save)
        print(ret)
    
    elif op == "CHANGEBG":
        if len(sys.argv)<7:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        R=int(sys.argv[3])
        B=int(sys.argv[4])
        G=int(sys.argv[5])
        save=sys.argv[6]
        ret=change_background_color(image,new_color=(R,B,G),save_path=save)
        print(ret)
        
    elif op == "MATTING":
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        save=sys.argv[3]
        ret=image_matting(image,save)
        print(ret)
        
    elif op == "DESHADOWING":
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        M=int(sys.argv[3])
        N=int(sys.argv[4])
        save=sys.argv[5]
        ret=remove_shadow(image,M,N,save)
        print(ret)
        
    elif op == "RECTIFICATION":
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        save=sys.argv[3]
        ret=image_rectification(image,save)
        print(ret)
        
    elif op == "CORRECT":
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        save=sys.argv[3]
        ret=image_correct(image,save)
        print(ret)
        
    elif op == "HIST":
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        save=sys.argv[3]
        ret=image_hist(image,save)
        print(ret)

    elif op == "CLAHE":
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        save=sys.argv[3]
        ret=image_clahe(image,save)
        print(ret)

    elif op == "LOG":
        if len(sys.argv)<4:
            sys.exit('缺少参数!')
        image=sys.argv[2]
        save=sys.argv[3]
        ret=image_log(image,save)
        print(ret)

    
    
    
    
    
    
    
    
    
    
    
    
    
    



    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    



















